import { QdrantClient } from '@qdrant/js-client-rest';
import { DocumentChunk, SearchResult } from './types';
import { AliBailianService, AliBailianConfig } from './ali-bailian-service';

export class VectorSearchService {
  private qdrantClient: QdrantClient;
  private aliBailianService: AliBailianService;
  private collectionName = 'document_chunks';

  constructor(aliBailianConfig?: AliBailianConfig) {
    // 初始化Qdrant客户端 - 你可以修改这些配置以匹配你的部署
    this.qdrantClient = new QdrantClient({
      url: 'http://localhost:6333', // 默认Qdrant端口
    });

    // 初始化阿里云百炼服务
    if (aliBailianConfig) {
      this.aliBailianService = new AliBailianService(aliBailianConfig);
    } else {
      // 从环境变量获取配置
      const apiKey = process.env.ALI_BAILIAN_API_KEY;
      if (!apiKey) {
        throw new Error('ALI_BAILIAN_API_KEY environment variable is required');
      }
      this.aliBailianService = new AliBailianService({
        apiKey,
        baseUrl: process.env.ALI_BAILIAN_BASE_URL,
      });
    }

    this.initializeCollection();
  }

  private async initializeCollection(): Promise<void> {
    try {
      // 检查集合是否存在
      const collections = await this.qdrantClient.getCollections();
      const exists = collections.collections.some(
        (collection) => collection.name === this.collectionName
      );

      if (!exists) {        // 创建集合，text-embedding-v3模型的维度是1024
        await this.qdrantClient.createCollection(this.collectionName, {
          vectors: {
            size: 1024, // text-embedding-v3 的维度
            distance: 'Cosine',
          },
        });
        console.error(`Created Qdrant collection: ${this.collectionName}`);
      }
    } catch (error) {
      console.error('Error initializing Qdrant collection:', error);
      // 在实际部署中，这里可能需要更好的错误处理
    }
  }
  async generateEmbedding(text: string): Promise<number[]> {
    try {
      return await this.aliBailianService.generateEmbedding(text, 'text-embedding-v3');
    } catch (error) {
      console.error('Error generating embedding:', error);
      throw new Error(`Failed to generate embedding: ${error}`);
    }
  }

  async addChunk(chunk: DocumentChunk): Promise<void> {
    try {
      // 生成嵌入向量
      const embedding = await this.generateEmbedding(chunk.content);
      
      // 添加到Qdrant
      await this.qdrantClient.upsert(this.collectionName, {
        points: [
          {
            id: this.hashString(chunk.id), // 使用哈希作为数字ID
            vector: embedding,
            payload: {
              filePath: chunk.filePath,
              content: chunk.content,
              startLine: chunk.startLine,
              endLine: chunk.endLine,
              chunkId: chunk.id,
            },
          },
        ],
      });
    } catch (error) {
      console.error(`Error adding chunk ${chunk.id}:`, error);
      throw error;
    }
  }

  async searchChunks(query: string, topK: number = 10): Promise<SearchResult[]> {
    try {
      // 生成查询嵌入
      const queryEmbedding = await this.generateEmbedding(query);
        // 在Qdrant中搜索
      const searchResult = await this.qdrantClient.search(this.collectionName, {
        vector: queryEmbedding,
        limit: topK,
        score_threshold: 0.3, // 降低相似度阈值，提高召回率
      });

      // 转换结果格式
      return searchResult.map((point) => ({
        filePath: point.payload?.filePath as string,
        content: point.payload?.content as string,
        startLine: point.payload?.startLine as number,
        endLine: point.payload?.endLine as number,
        score: point.score || 0,
      }));
    } catch (error) {
      console.error('Error searching chunks:', error);
      throw error;
    }
  }

  async removeChunksForFile(filePath: string): Promise<void> {
    try {
      // 搜索该文件的所有块
      const searchResult = await this.qdrantClient.scroll(this.collectionName, {
        filter: {
          must: [
            {
              key: 'filePath',
              match: {
                value: filePath,
              },
            },
          ],
        },
        limit: 10000, // 假设单个文件不会有超过10000个块
      });

      if (searchResult.points.length > 0) {
        const pointIds = searchResult.points.map((point) => point.id);
        await this.qdrantClient.delete(this.collectionName, {
          points: pointIds,
        });
      }
    } catch (error) {
      console.error(`Error removing chunks for file ${filePath}:`, error);
      throw error;
    }
  }

  // 简单的字符串哈希函数，将字符串转换为数字ID
  private hashString(str: string): number {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // 转换为32位整数
    }
    return Math.abs(hash);
  }
}
